package com.anonymous.server;

import java.io.BufferedReader;
import java.io.Console;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.SecureRandom;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.TrustManagerFactory;

import com.anonymous.model.UserList;
import com.anonymous.util.DatabaseUtils;
import com.anonymous.util.LoggerUtils;

public class Server {
	LoggerUtils logger = new LoggerUtils();

	/**
	 * sever keeps a userlist for all logged in users.
	 */
	@SuppressWarnings("rawtypes")
	private UserList userList;

	/**
	 * Use database utils to connect to SQLite database
	 */
	private DatabaseUtils dbUtils = DatabaseUtils.getInstance();

	/**	 * The port we will listen on
	 */
	private static int port = 6677;

	/**
	 * KeyStore for storing our public/private key pair
	 */
	private KeyStore clientKeyStore;

	/**
	 * Used to generate a SocketFactory
	 */
	private static SSLContext sslContext;

	/**
	 * A source of secure random numbers
	 */
	static private SecureRandom secureRandom;

	/**
	 * KeyStore for storing the server's public key
	 */
	private KeyStore serverKeyStore;

	/**
	 * Passphrase for accessing our authentication keystore
	 */
	private String passphrase;

	public DatabaseUtils getDbUtils() {
		return dbUtils;
	}

	@SuppressWarnings("rawtypes")
	public synchronized UserList getUserList() {
		return userList;
	}
	private void setupServerKeyStore()  {
		BufferedReader infromuser=new BufferedReader(new InputStreamReader(System.in));
		try{
			System.out.print("Put in passphrase : ");
			passphrase=infromuser.readLine();
		serverKeyStore = KeyStore.getInstance("JKS");
		serverKeyStore.load(new FileInputStream("server.private"),
				passphrase.toCharArray());
		}catch(Exception e){
			System.out.println("Wrong pass phrase");
			logger.LogSevere("Server:Wrong pass phrase for starting server.");
			setupServerKeyStore();
		}
	}

	private void setupClientKeyStore() throws GeneralSecurityException,
			IOException {
		clientKeyStore = null;
	}

	private void setupSSLContext() throws GeneralSecurityException, IOException {
		TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
		tmf.init(clientKeyStore);

		KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
		kmf.init(serverKeyStore, passphrase.toCharArray());

		sslContext = SSLContext.getInstance("TLS");
		sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(),
				secureRandom);
	}

	public Server() throws Exception {

		System.out.println("Setting up Server Keystore...");
		logger.LogNormal("Server: waiting for authentication. ");
		setupServerKeyStore();
		logger.LogNormal("Server: authentication sucess.");
		setupClientKeyStore();
		System.out.println("Wait while secure random numbers are initialized....");
		logger.LogNormal("Wait while secure random numbers are initialized....");
		secureRandom = new SecureRandom();
		secureRandom.nextInt();
		setupSSLContext();
		
		userList = new HashtableUserList(serverKeyStore,passphrase);
		new Thread((Runnable) userList).start();

	}

	// kickoff method to run server and listen for client connections
	public static void main(String[] args) throws Exception {
		SSLServerSocket SSLWelcomeSocket = null;
		Server server = new Server();
		boolean listening = true;

		try {
			
			// create a welcome socket on port
			SSLServerSocketFactory sf = sslContext.getServerSocketFactory();
			SSLWelcomeSocket = (SSLServerSocket) sf.createServerSocket(port);
			// Do not Require client authorization
			SSLWelcomeSocket.setNeedClientAuth(false);
		} catch (IOException e) {
			System.err.println("Could not listen on port: " + port);
	
			System.exit(-1);
		}
		System.out.println("Server running...\n");
		while (listening) {
			// every time a new client tries to connect to server, server
			// creates a new thread
			// to handle the socket.
			
			new ServerThread(SSLWelcomeSocket.accept(), server).start();
		}
	}
	
	public String getPassphrase() {
		return passphrase;
	}

	public KeyStore getServerKeyStore() {
		return serverKeyStore;
	}
}
